package com.netstar.library;

import java.util.HashMap;
import java.util.List;

import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.SystemClock;
import android.util.Log;

import com.netstar.SQLiteHelper;
import com.netstar.process.ProcessWatcher;
import com.netstar.service.NetService;
import com.netstar.util.EvtLog;

/**
 * 全局应用程序
 * 
 * @author zou.sq
 * @since 2013-04-13 下午04:29:24
 * @version 1.0
 */
public class NetStarApplication extends Application {
	public static final String TAG = "NetStarApplication";
	private static SQLiteDatabase sDatabase;
	public static Context CONTEXT;

	private static HashMap<String, SimpleAppInfo> sPackagesMap;

	private BroadcastReceiver mAppReceiver;

	private static class SimpleAppInfo {
		long appId;
		int uid;
		String name;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		sPackagesMap = new HashMap<String, SimpleAppInfo>();
		CONTEXT = getApplicationContext();
		sDatabase = getDatabase();
		importAppsToLocal(this);
		registerAppReceiver();
		startService(new Intent(this, NetService.class));
	}

	public static SQLiteDatabase getDatabase() {
		if (null != sDatabase) {
			return sDatabase;
		}
		return SQLiteHelper.getInstance(CONTEXT).getWritableDatabase();
	}

	/**
	 * @return -1 if not found.
	 */
	public static long getAppId(String pkg) {
		SimpleAppInfo info = sPackagesMap.get(pkg);
		if (null == info) {
			return -1;
		}
		return info.appId;
	}

	public static String getAppName(String pkg) {
		SimpleAppInfo info = sPackagesMap.get(pkg);
		if (null == info) {
			return pkg;
		}
		return info.name;
	}

	/**
	 * @return 0 if not found.
	 */
	public static int getAppUid(String pkg) {
		SimpleAppInfo info = sPackagesMap.get(pkg);
		if (null == info) {
			return 0;
		}
		return info.uid;
	}

	/**
	 * 
	 * @Title: importAppsToLocal
	 * @Description: 把已安装的app信息写入数据库，并切在本地记录下来
	 * @param @param context 设定文件
	 * @return void 返回类型
	 * @throws
	 */
	private void importAppsToLocal(Context context) {
		long startTime = 0;
		startTime = SystemClock.uptimeMillis();
		final SQLiteDatabase db = getDatabase();
		PackageManager pm = context.getPackageManager();
		List<PackageInfo> list = pm.getInstalledPackages(0);

		Cursor cursor = db.rawQuery("SELECT * FROM apps", null);
		while (cursor.moveToNext()) {
			String pkg = cursor.getString(cursor.getColumnIndex("_pkg"));

			SimpleAppInfo info = new SimpleAppInfo();
			info.appId = cursor.getLong(cursor.getColumnIndex("_id"));
			info.uid = cursor.getInt(cursor.getColumnIndex("_uid"));
			info.name = cursor.getString(cursor.getColumnIndex("_name"));
			sPackagesMap.put(pkg, info);
		}
		cursor.close();

		db.beginTransaction();
		try {
			for (PackageInfo packageInfo : list) {
				String pkgName = packageInfo.packageName;
				SimpleAppInfo sai = sPackagesMap.get(pkgName);
				String appName = null;
				int uid = 0;
				try {
					ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0);
					uid = appInfo.uid;
					appName = appInfo.loadLabel(pm).toString();
				} catch (PackageManager.NameNotFoundException e) {
				}

				/*
				 * Not recorded in the database, so add it.
				 */
				ContentValues values = new ContentValues();
				values.put("_pkg", pkgName);
				values.put("_uid", uid);
				values.put("_name", appName);

				if (sai == null) {
					long rowID = db.insert("apps", null, values);
					SimpleAppInfo info = new SimpleAppInfo();
					info.appId = rowID;
					info.uid = uid;
					info.name = appName;
					sPackagesMap.put(pkgName, info);
				} else {
					db.update("apps", values, "_pkg = ?", new String[] { pkgName });
					SimpleAppInfo info = new SimpleAppInfo();
					info.appId = sai.appId;
					info.uid = uid;
					info.name = appName;
					sPackagesMap.put(pkgName, info);
				}
			}
			db.setTransactionSuccessful();
		} finally {
			db.endTransaction();
		}
		Log.i(TAG, "read apps into memory in " + (SystemClock.uptimeMillis() - startTime) + " ms");
	}

	private void registerAppReceiver() {
		if (null == mAppReceiver) {
			mAppReceiver = new BroadcastReceiver() {

				@Override
				public void onReceive(Context context, Intent intent) {
					String pkg = intent.getData().getSchemeSpecificPart();
					final PackageManager pm = context.getPackageManager();
					String action = intent.getAction();
					if (action.equals(Intent.ACTION_PACKAGE_ADDED)) {
						if (!sPackagesMap.containsKey(pkg)) {
							/**
							 * The hash map does not contains this package, so
							 * add in.
							 */
							String appName = null;
							int uid = 0;
							try {
								ApplicationInfo appInfo = pm.getApplicationInfo(pkg, 0);
								uid = appInfo.uid;
								appName = appInfo.loadLabel(pm).toString();
							} catch (PackageManager.NameNotFoundException e) {
							}

							ContentValues values = new ContentValues();
							values.put("_pkg", pkg);
							values.put("_uid", uid);
							values.put("_name", appName);
							long rowID = getDatabase().insert("apps", null, values);
							if (rowID > 0) {
								SimpleAppInfo info = new SimpleAppInfo();
								info.appId = rowID;
								info.uid = uid;
								info.name = appName;
								sPackagesMap.put(pkg, info);
							}
						}
					} else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
						/**
						 * Contains the package that has just replaced, update
						 * its application name and uid(change or not?).
						 */
						String appName = null;
						int uid = 0;
						try {
							ApplicationInfo appInfo = pm.getApplicationInfo(pkg, 0);
							uid = appInfo.uid;
							appName = appInfo.loadLabel(pm).toString();
						} catch (PackageManager.NameNotFoundException e) {
						}

						SimpleAppInfo info = sPackagesMap.get(pkg);
						info.name = appName;
						info.uid = uid;
					} else {
						int uid = getAppUid(pkg);
						if (uid > 0) {
							getDatabase().delete("blocked_apps", "_uid=" + uid, null);
							ProcessWatcher.getDefault(CONTEXT).unwatch(uid);
						}
					}
				}
			};
		}
		IntentFilter filter = new IntentFilter();
		filter.addAction(Intent.ACTION_PACKAGE_ADDED);
		filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
		filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
		filter.addDataScheme("package");
		registerReceiver(mAppReceiver, filter);
	}

	@Override
	public void onTerminate() {
		super.onTerminate();
		EvtLog.i(TAG, "onTerminate");
		if (null != mAppReceiver) {
			unregisterReceiver(mAppReceiver);
			mAppReceiver = null;
		}
	}

}